<?php

namespace App\Repositories;

use App\Services\Tools\HelperService;
use App\Traits\GiftRank;
use App\Enums\LuckyTree;
use Illuminate\Support\Facades\DB;
use App\Exceptions\BasicException;

class LuckyTreeRepository
{
    use GiftRank;

    public function getJackpotList($type, $is_next = false)
    {
        $model = $is_next ? 'ln_lucky_tree_next' : 'ln_lucky_tree';
        $list = DB::table($model.' as a')
                  ->LeftJoin('ln_gift as b', 'b.id', '=', 'a.gift_id')
                  ->select([
                      'a.id',
                      'a.gift_id',
                      'a.number',
                      'a.critical_times',
                      'a.ratio',
                      'b.name as gift_name',
                      'b.price',
                      'b.picture',
                      'b.special',
                  ])
                  ->where('a.type', $type)
                  ->orderBy('b.price', 'desc')
                  ->orderBy('b.id', 'desc')
                  ->get()->map(function ($item, $key) {
                $item->quality = $this->giftRank($item->price);
                $item->key = $key + 1;

                return $item;
            });

        return $list;
    }

    //获取剩余次数
    public function getJackpotCount($type = 1, $is_next = false)
    {
        $model = $is_next ? 'model_lucky_tree_next' : 'model_lucky_tree';
        $total = app($model)->where('type', $type)->sum('number');

        return $total ?: 0;
    }

    //获取剩余总金额
    public function getJackpotTotal($type = 1, $is_next = false)
    {
        $model = $is_next ? 'ln_lucky_tree_next' : 'ln_lucky_tree';
        $total = DB::table($model.' as a')
                   ->LeftJoin('ln_gift as b', 'b.id', '=', 'a.gift_id')
                   ->where('a.type', $type)
                   ->sum(DB::raw('a.number * b.price'));

        return $total ?: 0;
    }

    public function getCriticalRatio($moduleId,$typeEnum,$typeId){
        $config = app('model_critical_pool_config')->where([
            'module' => $moduleId,
            'pool_type' => $typeEnum,
            'type_id' => $typeId,
        ])->first();
        if(!isset($config) || empty($config->toArray(false,false))){
            $ratio = LuckyTree::MODULE_DEFAULT_RATIO[$moduleId]??LuckyTree::TREE_DEFAULT_RATIO;
            $config = ['ratio'=>$ratio];
        }else{
            $config = $config->toArray(false,false);
        }
        return $config;
    }

    //替换奖池增加暴击奖池及数量
    public function replaceJackpotAddCritical($poolGiftList,$type,$userId){
        $typeEnum =  LuckyTree::TREE_TYPE_ENUM[$type]??0; //转换过的类型
        if(empty($typeEnum) || empty($poolGiftList)){   //非暴击奖池
            return true;
        }

        $typeId = 0;    //下次奖池使用的奖品类型id
        $coinNum = 0;
        foreach ($poolGiftList as $v){
            $typeId = $v['type'];
            $coinNum += $v['number'] * 200; //单个礼物算200
        }

        $coinNum = intval($coinNum);
        $moduleId = LuckyTree::MODULE_TREE;
        $isCommon = LuckyTree::TYPE_ENUM_TO_IS_COMMON[$typeEnum]??0;
        if($isCommon){
            $searchUserId = 0;
        }else{
            $searchUserId = $userId;
        }

        //入库
        $ratioDetail = $this->getCriticalRatio($moduleId,$typeEnum,$typeId);
        $ratio = $ratioDetail['ratio']/100;
        $criticalCoinLevel = app('model_critical_pool_coin_level')->where([
            'module' => $moduleId,
            'pool_type' => $typeEnum,
            'user_id' => $searchUserId,
        ])->first();
        $criticalCoinLevel = !isset($criticalCoinLevel)?[]:$criticalCoinLevel->toArray();
        $addCoinNum = (int)ceil(bcmul($ratio,$coinNum));
        $criticalConfig = [];

        if(empty($criticalCoinLevel)){
            $criticalConfig = [
                'module' => $moduleId,
                'level_coin_num' => $addCoinNum,
                'user_id' => $searchUserId,
                'pool_type' => $typeEnum,
            ];
            $res = app('model_critical_pool_coin_level')->insert($criticalConfig);
            $oldCoin = 0;
        }else{
            $oldCoin =  $criticalCoinLevel['level_coin_num'];
            if($addCoinNum){
                $res = app('model_critical_pool_coin_level')
                    ->where([
                        'id' => $criticalCoinLevel['id'],
                    ])->update([
                        'level_coin_num' =>DB::raw('level_coin_num + '.$addCoinNum ),
                    ]);
            }else{
                $res = true;
            }
        }

        if(empty($res)){
            throw new BasicException(0, '更新可用余额失败');
        }
        $poolConfig = [
            'poolGiftList' => $poolGiftList,
            'oldCoin' => $oldCoin,
            'criticalConfig' => $criticalConfig,
            'ratioDetail' => $ratioDetail,
        ];
        $dbData = [
            'module' => $moduleId,
            'gift_id' => 0,
            'user_id' => $userId,
            'pool_type' => $typeEnum,
            'coin_before' => $oldCoin,
            'coin_change' => $addCoinNum,
            'coin_after' => $oldCoin+$addCoinNum,
            'pool_config' => json_encode($poolConfig),
            'remark' => '更换奖池增加余额',
            'change_type' => LuckyTree::POOL_CHANGE_ADMIN,
            'pool_periods' => $dbConfig['poolPeriods']??1,
        ];
        $res = app('model_critical_coin_log')->insert($dbData);

        if(empty($res)){
            throw new BasicException(0, '更新可用余额失败!');
        }
        return  true;
    }

    public function replaceJackpot($type)
    {
        $type_next_map = LuckyTree::POOL_TYPE_MAP[$type];

        $nextPrizeConfig = $this->getJackpotNext($type_next_map);
        $oldList = app('model_lucky_tree')->where('type', $type)->get();
        if(!empty($oldList)){
            $oldList = $oldList->toArray();
            $oldList=  HelperService::indexToAssoc($oldList,'gift_id');
        }
        $insertList = [];
        foreach ($nextPrizeConfig as $item) {
            $oldCriticalNum = isset($oldList[$item['gift_id']])?$oldList[$item['gift_id']]['critical_times']:0;
            $insertList[] = [
                "type"     => $type,
                "number"   => $item['number'],
                "critical_times"   => $item['critical_times']+$oldCriticalNum,
                "gift_id"  => $item['gift_id'],
                "add_time" => date("Y-m-d H:i:s"),
                "remark"   => "由下期奖池覆盖替换而来",
            ];
        }
        if (!empty($insertList)) {
            DB::beginTransaction();
            try {
                app('model_lucky_tree')->where('type', $type)->delete();
                $this->replaceJackpotAddCritical($nextPrizeConfig,$type,0);
                app('model_lucky_tree')->insert($insertList);
            }catch (\Exception $e){
                DB::rollBack();
                throw new BasicException(0, $e->getMessage());
            }
            DB::commit();
        }
    }

    //获取下期奖池
    public function getJackpotNext($type = 3)
    {
        $where = [
            ['a.sold', 1],
            ['a.type', $type],
        ];
        if ($type != 5) {
            $where[] = ['a.number', '>', 0];
        }

        $list =  app('model_lucky_tree_next')->from('ln_lucky_tree_next as a')
                  ->LeftJoin('ln_gift as b', 'b.id', '=', 'a.gift_id')
                  ->select([
                      'a.gift_id',
                      'a.number',
                      'a.critical_times',
                      'a.ratio',
                      'b.price',
                      'a.type',
                  ])
                  ->where($where)
                  ->orderBy('a.ratio', 'desc')->get();
        $list = empty($list)?[]:$list->toArray();
        return $list;
    }

    /**
     * 获取特殊奖池统计数据
     */
    public function specialGiftList($params)
    {
        $redis = app('redis');

        $theory = $all = $current = [
            'times'    => 0,
            'in_coin'  => 0,
            'out_coin' => 0,
            'ratio'    => 0,
        ];
        $list = DB::table('ln_lucky_tree as base')
                  ->select(['base.number', 'g.price'])
                  ->leftJoin('ln_gift as g', 'base.gift_id', '=', 'g.id')
                  ->where('base.type', $params['type'])
                  ->get();
        if (!$list->isEmpty()) {
            foreach ($list as $value) {
                $theory['times'] += $value->number;
                $theory['out_coin'] += $value->number * $value->price;
            }
            $theory['in_coin'] = $theory['times'] * app('model_config')->getValue('WATERDROP_PRICE');
            $theory['ratio'] = $theory['in_coin'] == 0 ? 0 : round($theory['out_coin'] / $theory['in_coin'], 2);
        }
        // 用户中奖记录
        $current['in_coin'] = $redis->get('fish:special_incoin_total');
        $current['out_coin'] = $redis->get('fish:special_outcoin_total');
        $current['times'] = $redis->get('fish:special_times_total');
        if (empty($current['in_coin']) || empty($current['out_coin'])) {
            $recordList = DB::table('ln_lucky_tree_user_record_special')->selectRaw('sum(incoin_total) as in_coin,sum(outcoin_total) as out_coin,sum(number) as times')->first();
            $current['in_coin'] = $recordList->in_coin ?? 0;
            $current['out_coin'] = $recordList->out_coin ?? 0;
            $current['times'] = $recordList->times ?? 0;
            $redis->set('fish:special_incoin_total', $current['in_coin']);
            $redis->set('fish:special_outcoin_total', $current['out_coin']);
            $redis->set('fish:special_times_total', $current['times']);
        }

        if ($current['in_coin'] > 0 && $current['out_coin'] > 0) {
            $current['ratio'] = round($current['out_coin'] / $current['in_coin'], 2);

            if ($current['in_coin'] > $theory['in_coin'] && $current['out_coin'] > $theory['out_coin']) {
                $timesIncoin = ceil($current['in_coin'] / $theory['in_coin']);
                $timesOutcoin = ceil($current['out_coin'] / $theory['out_coin']);
                $times = min($timesIncoin, $timesOutcoin) - 1;
                $all['process_incoin'] = (1 - $times) * $theory['in_coin'] + $current['in_coin'];
                $all['process_outcoin'] = (1 - $times) * $theory['out_coin'] + $current['out_coin'];
                $all['ratio'] = round($all['process_outcoin'] / $all['process_incoin'], 2);
            } else {
                $all['process_incoin'] = $all['process_outcoin'] = 0;
                $all['ratio'] = round(($theory['out_coin'] + $current['out_coin']) / ($theory['in_coin'] + $current['in_coin']),
                    2);
            }
        } else {
            $all['ratio'] = $theory['in_coin'] <= 0 ? 0 : round($theory['out_coin'] / $theory['in_coin'], 2);
        }
        if (isset($params['all'])) {
            return ['all_ratio' => $all['ratio'], 'theory_ratio' => $theory['ratio']];
        }
        $key = 'fish:ratio_config';
        $ratioConfig = $redis->get($key);
        if (empty($ratioConfig)) {
            $ratioConfig = json_encode([
                'min_ratio'      => 0.8,
                'max_ratio'      => 1.2,
                'min_self_ratio' => 0.7,
                'max_self_ratio' => 1.4,
            ]);
            $redis->set($key, $ratioConfig);
        }

        $resultAll = [];
        $resultAll['in_coin'] = !empty($all['process_incoin']) ? ($theory['in_coin'].' + '.($all['process_incoin'] - $theory['in_coin'])) : ($theory['in_coin'].' + '.$current['in_coin']);
        $resultAll['out_coin'] = !empty($all['process_incoin']) ? ($theory['out_coin'].' + '.($all['process_outcoin'] - $theory['out_coin'])) : ($theory['out_coin'].' + '.$current['out_coin']);
        $resultAll['ratio'] = $all['ratio'];

        return [
            'theory'       => $theory,
            'all'          => $resultAll,
            'current'      => $current,
            'ratio_config' => json_decode($ratioConfig, true),
        ];
    }

    public function getRecord($request)
    {
        $isFlutter = $request->input('is_flutter', -1);
        $datemin = strtotime($request->input('datemin', 0));
        $datemax = $request->input('datemax', 0);
        $datemax = strtotime($datemax." 23:59:59");
        $where = [];
        //条件查询
        if (!empty($datemin) && !empty($datemax)) {
            $where [] = [
                function ($query) use ($datemin, $datemax) {
                    $query->whereBetween('a.add_time', [$datemin, $datemax]);
                },
            ];
        } elseif (!empty($datemin)) {
            $where[] = ['a.add_time', '>=', $datemin];
        } elseif (!empty($datemax)) {
            $where[] = ['a.add_time', '<=', $datemax];
        }
        $keyword = $request->input('keyword', '');
        if ($keyword) {
            $user_ids = app('model_user_data')->where('user_code', '=', "$keyword")->orWhere('nickname', '=',
                "$keyword")->pluck('user_id');
            if ($user_ids) {
                $where[] = [
                    function ($query) use ($user_ids) {
                        $query->whereIn('a.user_id', $user_ids);
                    },
                ];
            }
        }

        $gift_id = $request->input('gift_id', 0);
        if ($gift_id > 0) {
            $where[] = ['a.gift_id', $gift_id];
        }

        if ($isFlutter == 1) {
            $where[] = ['c.price', '>=', 99999];
        } else if ($isFlutter == 0) {
            $where[] = ['c.price', '<', 99999];
        }

        $field = [
            'a.id',
            'a.user_id',
            'a.gift_id',
            'a.add_time',
            'a.number',
            'b.nickname',
            'c.name as gift_name',
            'c.price as gift_price',
            'b.user_code',
        ];
        $perPage = $request->input('perPage', 20);
        $page = $request->input('page', 1);

        if(!empty($where)){
            $list = DB::table('ln_lucky_tree_log as a')->select($field)
                ->leftJoin('ln_user_data as b', 'a.user_id', '=', 'b.user_id')
                ->leftJoin('ln_gift as c', 'a.gift_id', '=', 'c.id')
                ->where($where)->orderByDesc('a.id')->paginate($perPage);
            $data = $list->items();
            $page = $list->currentPage();
            $limit = $list->perPage();
            $next = $list->nextPageUrl();
            $total = $list->total();
            $request = [
                'list' => $data,
                'meta' => [
                    'page' => $page,
                    'limit' => $limit,
                    'next' => $next,
                    'total' => $total
                ]
            ];
        }else{
            $minId = app('model_lucky_tree_log')->min('id');
            $maxId = app('model_lucky_tree_log')->max('id');
            $endId = $maxId - ($page - 1) * $perPage;
            $startId = $endId - $perPage;
            $where = [['a.id', '>', $startId], ['a.id', '<=', $endId]];
            $list = DB::table('ln_lucky_tree_log as a')->select($field)
                ->leftJoin('ln_user_data as b', 'a.user_id', '=', 'b.user_id')
                ->leftJoin('ln_gift as c', 'a.gift_id', '=', 'c.id')
                ->where($where)
                ->orderByDesc('a.id')
                ->get()->toArray();
            $request = [
                'list' => $list,
                'meta' => [
                    'limit' => $perPage,
                    'next' => null,
                    'page' => $page,
                    'total' => $maxId - $minId + 1,
                    ]
            ];
        }
        return $request;
//        return $list;
    }
}
